package practice.library.gremlin_scala.trial.friends_group.script

import com.thinkaurelius.titan.core.schema.{EdgeLabelMaker, PropertyKeyMaker, TitanGraphIndex, TitanManagement, VertexLabelMaker}
import com.thinkaurelius.titan.core._
import com.thinkaurelius.titan.graphdb.database.StandardTitanGraph
import com.thinkaurelius.titan.graphdb.transaction.StandardTitanTx
import gremlin.scala.ScalaGraph
import utility.CustomLogger

import scala.util.{Failure, Success, Try}

/**
  * Created by lovepocky on 16/7/22.
  */
object Manager extends CustomLogger {

	object PropertyKey {

		object Create {
			def timeStamp(mgmt: TitanManagement): Try[PropertyKey] = {
				Common.makePropertyKey(mgmt, _.makePropertyKey("timeStamp").dataType(classOf[java.lang.Long]).cardinality(Cardinality.SINGLE))
			}

			def authorId(mgmt: TitanManagement): Try[PropertyKey] = {
				Common.makePropertyKey(mgmt, _.makePropertyKey("authorId").dataType(classOf[java.lang.Long]).cardinality(Cardinality.SINGLE))
			}


			/** pointer */
			def ownerId(mgmt: TitanManagement): Try[PropertyKey] = {
				Common.makePropertyKey(mgmt, _.makePropertyKey("ownerId").dataType(classOf[java.lang.Long]).cardinality(Cardinality.SINGLE))
			}
		}

	}

	object VertexLabel {

		import practice.library.gremlin_scala.trial.friends_group.model.Vertex.label

		object Create {
			def article(mgmt: TitanManagement): Try[VertexLabel] = {
				Common.makeVertexLabel(mgmt, _.makeVertexLabel(label.article))
			}

			def pointer_article(mgmt: TitanManagement): Try[VertexLabel] = {
				Common.makeVertexLabel(mgmt, _.makeVertexLabel(label.pointer_article))
			}
		}

	}

	object EdgeLabel {

		import practice.library.gremlin_scala.trial.friends_group.model.Edge.label

		object Create {
			def pointer_readBy(mgmt: TitanManagement) = {
				Common.makeEdgeLabel(mgmt, _.makeEdgeLabel(label.pointer_readBy).unidirected())
			}
		}

	}


	object Index {

		object MixedIndex {

			import org.apache.tinkerpop.gremlin.structure.Vertex
			import practice.library.gremlin_scala.trial.friends_group.model.Vertex.label

			object Create {

				def es_by_ownerId_timeStamp_of_pointer_article(mgmt: TitanManagement) = {
					val indexName = "es_by_ownerId_timeStamp_of_pointer_article"
					Common.makeMixedIndex(mgmt, "search", indexName,
						mgmt => {
							val timeStamp: PropertyKey =
								if (mgmt.containsPropertyKey("timeStamp")) {
									mgmt.getPropertyKey("timeStamp")
								} else {
									PropertyKey.Create.timeStamp(mgmt) match {
										case Success(s) => s
										case Failure(e) => throw e
									}
								}
							val ownerId: PropertyKey =
								if (mgmt.containsPropertyKey("ownerId")) {
									mgmt.getPropertyKey("ownerId")
								} else {
									PropertyKey.Create.ownerId(mgmt) match {
										case Success(s) => s
										case Failure(e) => throw e
									}
								}
							val pointer_articleSchema =
								if (mgmt.containsVertexLabel(label.pointer_article)) {
									mgmt.getVertexLabel(label.pointer_article)
								} else {
									VertexLabel.Create.pointer_article(mgmt) match {
										case Success(s) => s
										case Failure(e) => throw e
									}
								}
							mgmt.buildIndex(indexName, classOf[Vertex]).addKey(ownerId).addKey(timeStamp).indexOnly(pointer_articleSchema)
						})
				}

				def es_by_timeStamp_authorId_of_article(mgmt: TitanManagement) = {

					Common.makeMixedIndex(mgmt, "search", "es_by_timeStamp_authorId_of_article",
						mgmt => {
							val timeStamp: PropertyKey =
								if (mgmt.containsPropertyKey("timeStamp")) {
									mgmt.getPropertyKey("timeStamp")
								} else {
									PropertyKey.Create.timeStamp(mgmt) match {
										case Success(s) => s
										case Failure(e) => throw e
									}
								}
							val authorId: PropertyKey =
								if (mgmt.containsPropertyKey("authorId")) {
									mgmt.getPropertyKey("authorId")
								} else {
									PropertyKey.Create.authorId(mgmt) match {
										case Success(s) => s
										case Failure(e) => throw e
									}
								}
							val articleSchema =
								if (mgmt.containsVertexLabel(label.article)) {
									mgmt.getVertexLabel("article")
								} else {
									VertexLabel.Create.article(mgmt) match {
										case Success(s) => s
										case Failure(e) => throw e
									}
								}
							loggers.console.info(s"$timeStamp, $authorId, $articleSchema")
							mgmt.buildIndex("es_by_timeStamp_authorId_of_article", classOf[Vertex]).addKey(timeStamp).addKey(authorId).indexOnly(articleSchema)
						})
				}
			}

		}


	}


	object Common {

		def closeAllTransactions(g: ScalaGraph[StandardTitanGraph]): Try[Int] = {
			import com.thinkaurelius.titan.graphdb.transaction.StandardTitanTx
			import scala.collection.JavaConversions.asScalaSet
			if (g.graph.getCurrentThreadTx.isOpen){
				g.graph.tx().rollback()
			}

			asScalaSet(g.graph.getOpenTransactions).map(_.asInstanceOf[StandardTitanTx]).foreach(g.graph.closeTransaction)

			g.graph.getOpenTransactions.size() match{
				case 0 => Success(0)
				case _ => Failure(new Exception(s"g.graph.getOpenTransactions.size() == ${g.graph.getOpenTransactions.size()}"))
			}
		}

		def awaitGraphIndexStatus(g: ScalaGraph[TitanGraph], indexName: String) = {
			import com.thinkaurelius.titan.graphdb.database.management.ManagementSystem
			ManagementSystem.awaitGraphIndexStatus(g.graph, indexName)
		}

		//todo
		def fixIndexStatus() = {

		}

		def makePropertyKey(mgmt: TitanManagement, propertyKeyMaker: TitanManagement => PropertyKeyMaker): Try[PropertyKey] = {
			//g.tx().rollback()
			val name = propertyKeyMaker(mgmt).getName
			if (!mgmt.containsPropertyKey(name)) {
				val key = propertyKeyMaker(mgmt).make()
				Success(key)
			} else {
				Failure(new Exception(s"$name is exist"))
			}
		}

		def makeVertexLabel(mgmt: TitanManagement, vertexLabelMaker: TitanManagement => VertexLabelMaker): Try[VertexLabel] = {
			val name = vertexLabelMaker(mgmt).getName
			if (!mgmt.containsPropertyKey(name)) {
				val key = vertexLabelMaker(mgmt).make()
				Success(key)
			} else {
				Failure(new Exception(s"$name is exist"))
			}

		}

		def makeEdgeLabel(mgmt: TitanManagement, edgeLabelMaker: TitanManagement => EdgeLabelMaker): Try[EdgeLabel] = {
			val name = edgeLabelMaker(mgmt).getName
			if (!mgmt.containsPropertyKey(name)) {
				val key = edgeLabelMaker(mgmt).make()
				Success(key)
			} else {
				Failure(new Exception(s"$name is exist"))
			}
		}

		def makeMixedIndex(mgmt: TitanManagement, backendIndexName: String, indexName: String, indexBuilder: TitanManagement => TitanManagement.IndexBuilder): Try[TitanGraphIndex] = {
			if (!mgmt.containsGraphIndex(indexName)) {
				val index = indexBuilder(mgmt).buildMixedIndex(backendIndexName)
				Success(index)
			} else {
				Failure(new Exception(s"$indexName is exist"))
			}
		}
	}

}
